package com.yfp.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hy.corecode.idgen.WFGIdGenerator;
import com.yfp.common.core.constant.CacheConstants;
import com.yfp.common.core.exception.ServiceException;
import com.yfp.common.datascope.annotation.DataScope;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.ActivityDTO;
import com.yfp.operation.domain.dto.InviteRecordDTO;
import com.yfp.operation.domain.dto.ParticipationDTO;
import com.yfp.operation.domain.vo.ActivityVO;
import com.yfp.operation.domain.vo.InviteRecordVO;
import com.yfp.operation.domain.vo.ParticipationDetailVO;
import com.yfp.operation.domain.vo.PassiveCountVO;
import com.yfp.operation.enums.CouponStatus;
import com.yfp.operation.mapper.*;
import com.yfp.operation.mapper.*;
import com.yfp.operation.service.MarActivityService;
import com.yfp.operation.service.OrderComboService;
import com.yfp.operation.domain.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.RedissonMultiLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 *
 * @description 针对表【mar_activity(活动)】的数据库操作Service实现
 * @createDate 2024-07-16 16:11:30
 */
@Slf4j
@Service
public class MarActivityServiceImpl extends ServiceImpl<MarActivityMapper, MarActivity> implements MarActivityService {

    @Resource
    private MarActivityMapper marActivityMapper;
    @Resource
    private MarketingMapper marketingMapper;
    @Resource
    private MarActivityDetailsMapper marActivityDetailsMapper;
    @Resource
    private MarActivityClientMapper marActivityClientMapper;
    @Resource
    private MarCouponMapper marCouponMapper;
    @Resource
    private WFGIdGenerator wfgIdGenerator;
    @Resource
    private OrderComboService orderComboService;
    @Resource
    private ClientCouponMapper clientCouponMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MarActivityPositionMapper marActivityPositionMapper;

    /**
     * 新增
     *
     * @param marActivity
     */
    @Override
    @Transactional
    public void add(MarActivity marActivity) {

        // 创建指定点位活动前提  必须存在全部点位活动
        if (marActivity.getPosition().equals(1)) {
            LambdaQueryWrapper<MarActivity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MarActivity::getPosition, 1);
            wrapper.eq(MarActivity::getCityName, marActivity.getCityName());
            wrapper.eq(MarActivity::getStatus, CouponStatus.ONE.getStatus());
            MarActivity activity = marActivityMapper.selectOne(wrapper);
            if (!BeanUtil.isEmpty(activity)) {
                throw new ServiceException("同城市只能存在一个普通全部点位的活动！");
            }
        }

        if (marActivity.getPosition().equals(3)) {
            LambdaQueryWrapper<MarActivity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MarActivity::getPosition, 3);
            wrapper.eq(MarActivity::getCityName, marActivity.getCityName());
            wrapper.eq(MarActivity::getStatus, CouponStatus.ONE.getStatus());
            MarActivity activity = marActivityMapper.selectOne(wrapper);
            if (!BeanUtil.isEmpty(activity)) {
                throw new ServiceException("同城市只能存在一个特殊全部点位的活动！");
            }
        }


        // 当前登录用户
        Long userId = SecurityUtils.getLoginUser().getSysUser().getUserId();
//        Long userId = 69L;
        marActivity.setCreateUserId(userId);
        marActivity.setUpdateUserId(userId);
        marActivity.setDeptId(SecurityUtils.getLoginUser().getSysUser().getDeptId());
//        marActivity.setDeptId(1L);

        long startTime = marActivity.getStartTime().getTime();
        long endTime = marActivity.getEndTime().getTime();
        long time1 = new Timestamp(System.currentTimeMillis()).getTime();

        if (startTime <= time1 && endTime >= time1) {
            marActivity.setStatus(CouponStatus.ONE.getStatus());
        } else if (endTime < time1) {
            marActivity.setStatus(CouponStatus.TWO.getStatus());
        } else if (time1 < startTime) {
            marActivity.setStatus(CouponStatus.FOUR.getStatus());
        }

        LambdaQueryWrapper<MarActivity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MarActivity::getCityName, marActivity.getCityName());
        wrapper.eq(MarActivity::getStatus, CouponStatus.ONE.getStatus());
        wrapper.eq(MarActivity::getPosition, marActivity.getPosition());
        List<MarActivity> marActivityList = marActivityMapper.selectList(wrapper);


        if (!CollUtil.isEmpty(marActivityList)) {
            // 全部点位的话，将之前的失效    指定点位的话  判断本次的点位是否与之前的点位存在交集，有交集则新增失败
            // 普通全部或特殊全部
            if (marActivity.getPosition().equals(1) || marActivity.getPosition().equals(3)) {
                throw new ServiceException("您新增的活动与全局邀请有礼活动冲突，该活动具有唯一性，请参考最新规则调整");
            } else {

                List<Long> activityIds = marActivityList.stream().map(item -> item.getId()).toList();
                List<MarActivityPosition> mapList = marActivityPositionMapper.getByActivityId(activityIds);
                List<String> positionIds = mapList.stream().map(item -> item.getPositionId()).toList();

                boolean b = marActivity.getPositionIdList().stream().anyMatch(positionIds::contains);
                if (b) {
                    throw new ServiceException("您新增的活动和特殊点位规则冲突，此点位不允许多个邀请有礼活动，请按最新规则修改");
                }
            }
        }


        marActivity.setCreateTime(new Timestamp(System.currentTimeMillis()));
        marActivity.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        long marketingId = wfgIdGenerator.next();
        marActivity.setMarketingId(marketingId);
        // 活动表
        marActivityMapper.add(marActivity);

        // 活动子表
        marActivityDetailsMapper.add(marActivity);

//        if (marActivity.getPosition() == 1) {
//            // 获取当前城市的被指定点位  状态为进行中、待开始
//            List<String> appointPositionIds = marActivityPositionMapper.appointPosition(marActivity.getCityName(),2);
//
//            // 根据城市获取普通点位id
//            List<String> positionIds = marActivityPositionMapper.getPositionIds(marActivity.getCityName(),2);
//            if (!CollUtil.isEmpty(appointPositionIds)) {
//                positionIds.removeAll(appointPositionIds);
//            }
//            marActivity.setPositionIdList(positionIds);
//        }
//
//        if (marActivity.getPosition() == 3) {
//            // 获取当前城市的被指定点位  状态为进行中、待开始
//            List<String> appointPositionIds = marActivityPositionMapper.appointPosition(marActivity.getCityName(),4);
//
//            // 根据城市获取特殊点位id
//            List<String> positionIds = marActivityPositionMapper.getPositionIds(marActivity.getCityName(),1);
//            if (!CollUtil.isEmpty(appointPositionIds)) {
//                positionIds.removeAll(appointPositionIds);
//            }
//            marActivity.setPositionIdList(positionIds);
//        }

        // 营销主表
        Marketing marketing = new Marketing();
        marketing.setId(marketingId);
        marketing.setMarActivityId(marActivity.getId());
        marketing.setType(CouponStatus.TWO.getStatus());
        marketingMapper.add(marketing);

        // 邀请活动关联点位
        if (!CollUtil.isEmpty(marActivity.getPositionIdList())) {
            marActivityPositionMapper.adds(marActivity.getPositionIdList(),marActivity.getId());
        }

    }

    /**
     * 活动列表
     *
     * @param activityDTO
     * @return
     */
    @Override
    @DataScope(deptAlias = "ma")
    public List<ActivityVO> selectMarActivity(ActivityDTO activityDTO) {
        List<ActivityVO> list = marActivityMapper.marActivityList(activityDTO);
        return list;
    }

    /**
     * 活动列表数据补全
     *
     * @param list
     * @return
     */
    @Override
    public List<ActivityVO> complement(List<ActivityVO> list) {

        if (list.isEmpty()) {
            return new ArrayList<>();
        }
        // 获取活动id
        List<Long> ids = list.stream().map(activityVO -> activityVO.getId()).collect(Collectors.toList());

        // 指定点位的活动id
        List<Long> activityIds = list.stream().filter(item -> item.getPosition() == 2 || item.getPosition() == 4).map(item -> item.getId()).toList();
//        List<MarActivityPosition> mapList = null;
//        if (!CollUtil.isEmpty(activityIds)) {
//            mapList = marActivityPositionMapper.getByActivityId(activityIds);
//        }


        List<PassiveCountVO> countVOS = marActivityClientMapper.getPassiveCount(ids);

        if (countVOS.isEmpty()) {
            return list;
        }

        Map<Long, Integer> countMap = countVOS.stream().collect(Collectors.toMap(PassiveCountVO::getMarActivityId, PassiveCountVO::getPassiveCount));

        for (ActivityVO activityVO : list) {
            activityVO.setCount(0);
            if (countMap.containsKey(activityVO.getId())) {
                activityVO.setCount(countMap.get(activityVO.getId()));
            }

            List<String> positionNames = new ArrayList<>();
            if (activityVO.getPosition() == 2) {
                positionNames = marActivityPositionMapper.getPositionNames(2,activityVO.getId());
            }
            if (activityVO.getPosition() == 4) {
                positionNames = marActivityPositionMapper.getPositionNames(1,activityVO.getId());
            }

            activityVO.setPositionNames(positionNames);
        }
        return list;
    }

    /**
     * 邀请列表
     *
     * @param inviteRecordDTO
     * @return
     */
    @Override
    public List<InviteRecordVO> inviteRecord(InviteRecordDTO inviteRecordDTO) {
        List<InviteRecordVO> list = marActivityClientMapper.inviteRecord(inviteRecordDTO);
        return list;
    }

    /**
     * 邀请列表数据补全
     *
     * @param list
     * @return
     */
    @Override
    public List<InviteRecordVO> invitecomplement(List<InviteRecordVO> list) {
        return list;
    }

    /**
     * 参与详情
     * <p>
     * 用户查的哪个表，如果是client的话账号是什么
     * 奖励是已下单的才算吗
     *
     * @param participationDTO
     * @return
     */
    @Override
    public List<ParticipationDetailVO> participation(ParticipationDTO participationDTO) {
        List<ParticipationDetailVO> list = marActivityClientMapper.participation(participationDTO);
        return list;
    }

    @Override
    public List<ClientCoupon> findActivityAward(ParticipationDTO participationDTO) {
        return clientCouponMapper.findActivityAward(participationDTO);
    }


    /**
     * 根据id获取活动详情
     *
     * @param marActivityId
     * @return
     */
    @Override
    public MarActivity selectById(Long marActivityId) {
        MarActivity marActivity = marActivityMapper.selectById(marActivityId);
        // 根据活动id获取邀请人和被邀请人的优惠券
        MarActivityDetails marActivityDetails = marActivityDetailsMapper.getByMarActivityId(marActivityId);

        if (marActivity.getPosition().equals(2) || marActivity.getPosition().equals(4)) {
            ArrayList<Long> longs = new ArrayList<>();
            longs.add(marActivityId);
            List<MarActivityPosition> activityPositions = marActivityPositionMapper.getByActivityId(longs);
            List<String> positionIds = activityPositions.stream().map(item -> item.getPositionId()).toList();
            marActivity.setPositionIdList(positionIds);
        }


        if (marActivityDetails != null ) {
            String hostCouponName = marCouponMapper.selectById(marActivityDetails.getHostMarCouponId()).getCouponName();
            marActivity.setHostCouponName(hostCouponName);
            marActivity.setHostCouponId(marActivityDetails.getHostMarCouponId());
        }
        return marActivity;
    }

    /**
     * 修改状态
     *
     * @param marActivityId
     * @param status
     */
    @Override
    public void updateStatus(Long marActivityId, Integer status) {
        marActivityMapper.updateStatus(marActivityId, status);
    }

    @Override
    public void callUpdateMarActivityStatus() {
        marActivityMapper.callUpdateMarActivityStatus();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void issueInviteCoupon(String passiveClientId) throws InterruptedException {
        log.info("被邀请人id:{}", passiveClientId);
        // 判断被邀请人是否有拉新活动
        MarActivity marActivity = marActivityMapper.selectByPassiveClientIdAndType(passiveClientId, 1);
        if (Objects.isNull(marActivity)) {
            log.info("被邀请人id:{},被邀请人不在拉新活动中", passiveClientId);
            return;
        }
        log.info("被邀请人id:{},参加的活动id:{}", passiveClientId, marActivity.getId());
        // 判断是否在有效期时间内
        DateTime nowDate = DateUtil.date();
        if (nowDate.isBefore(marActivity.getStartTime()) || nowDate.isAfter(marActivity.getEndTime())) {
            log.info("被邀请人id:{},拉新活动时间未到", passiveClientId);
            return;
        }
        // 判断被邀请人是否为新用户
        LambdaQueryWrapper<OrderComboDO> queryWrapper = Wrappers.lambdaQuery(OrderComboDO.class).eq(OrderComboDO::getUserId, passiveClientId).eq(OrderComboDO::getGoodsType, 1).eq(OrderComboDO::getStatus,"Finish");
        long count = orderComboService.count(queryWrapper);
        if (count >= 2) {
            // count==1 时，为新用户，当count大于1时已经购买过商品
            log.info("被邀请人id:{},被邀请人已经购买过商品", passiveClientId);
            return;
        }

        MarActivityDetails marActivityDetails = marActivityDetailsMapper.getByMarActivityId(marActivity.getId());
        MarActivityClient marActivityClient = marActivityClientMapper.selectByActivityIdAndPassiveClientId(marActivity.getId(), passiveClientId);
        String hostClientId = marActivityClient.getHostClientId();

        // RLock lock1 = redissonClient.getLock(CacheConstants.MAR_COUPON_SURPLUSCOUNT_LOCK_KEY + marActivityDetails.getPassiveMarCouponId());
        RLock lock2 = redissonClient.getLock(CacheConstants.MAR_COUPON_SURPLUSCOUNT_LOCK_KEY + marActivityDetails.getHostMarCouponId());
        RedissonMultiLock redissonMultiLock = new RedissonMultiLock(lock2);
        if (!redissonMultiLock.tryLock(5, TimeUnit.SECONDS)) {
            log.info("被邀请人id:{},获取锁失败!", passiveClientId);
            return;
        }

        try {
            // MarCoupon passiveCoupon = marCouponMapper.selectById(marActivityDetails.getPassiveMarCouponId());
            MarCoupon hostMarCoupon = marCouponMapper.selectById(marActivityDetails.getHostMarCouponId());

            // if (NumberUtil.equals(passiveCoupon.getId(), hostMarCoupon.getId()) && passiveCoupon.getSurplusCount() <= 1) {
            //     log.info("优惠券剩余数量不够分配");
            //     marActivityClientMapper.updateStatusById(marActivityClient.getId(), 2);
            //     return;
            // }

            if (extracted(hostClientId, hostMarCoupon, nowDate)) {
                // 给被邀请人发放优惠券
                // log.info("给被邀请人发放优惠券:clientId:{},couponId:{}", passiveClientId, passiveCoupon.getId());
                // this.issueInviteCoupon(passiveClientId, passiveCoupon, nowDate);
                // 给邀请人发放优惠券
                log.info("被邀请人id:{},给邀请人发放优惠券:clientId:{},couponId:{}!", passiveClientId, hostClientId, hostMarCoupon.getId());
                ClientCoupon clientCoupon = this.issueInviteCoupon(hostClientId, hostMarCoupon, nowDate);
                marActivityClientMapper.updateStatusById(marActivityClient.getId(), clientCoupon.getId(), 1);
                log.info("被邀请人id:{},发放成功!", passiveClientId);
            } else {
                marActivityClientMapper.updateStatusById(marActivityClient.getId(), null, 2);
            }
        } finally {
            redissonMultiLock.unlock();
        }
    }

    /**
     * 修改活动
     *
     * @param marActivity
     */
    @Override
    @Transactional
    public void updateActivity(MarActivity marActivity) {

        long startTime = marActivity.getStartTime().getTime();
        long endTime = marActivity.getEndTime().getTime();
        long time1 = new Timestamp(System.currentTimeMillis()).getTime();

        if (startTime <= time1 && endTime >= time1) {
            marActivity.setStatus(CouponStatus.ONE.getStatus());
        } else if (endTime < time1) {
            marActivity.setStatus(CouponStatus.TWO.getStatus());
        } else if (time1 < startTime) {
            marActivity.setStatus(CouponStatus.FOUR.getStatus());
        }





        marActivityMapper.updateActivity(marActivity);

        // 活动子表
        marActivityDetailsMapper.updateActivityCoupon(marActivity);


        // 邀请活动关联点位
        if (!CollUtil.isEmpty(marActivity.getPositionIdList())) {
            // 删除点位关系表
            marActivityPositionMapper.deleteByActivityId(marActivity.getId());
            marActivityPositionMapper.adds(marActivity.getPositionIdList(),marActivity.getId());
        }

    }

    private ClientCoupon issueInviteCoupon(String clientId, MarCoupon coupon, DateTime nowDate) {

        // 领取后指定天数有效时间处理
        if (null != coupon.getValidDays()) {
            // 当前日期
            LocalDate currentDate = LocalDate.now();
            // 要添加的天数
            int daysToAdd = coupon.getValidDays();
            // 当前日期加上指定天数
            LocalDate newDate = currentDate.plusDays(daysToAdd);
            // 获取结果日期的起始时间（00:00:00）
            LocalDateTime startOfDay = newDate.atStartOfDay();
            LocalDateTime localDateTime = startOfDay.minusSeconds(1);
            // 转换为Instant
            Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
            // 转换为Timestamp
            Timestamp timestamp = Timestamp.from(instant);
            coupon.setValidStartTime(new Timestamp(System.currentTimeMillis()));
            coupon.setValidEndTime(timestamp);
        }

        ClientCoupon clientCouponPassive = BeanUtil.toBean(coupon, ClientCoupon.class);
        clientCouponPassive.setId(null);
        clientCouponPassive.setClientId(clientId);
        clientCouponPassive.setCouponId(coupon.getId());
        clientCouponPassive.setCreateTime(nowDate);
        clientCouponMapper.insert(clientCouponPassive);
        marCouponMapper.editSurplusCount(coupon.getId());
        return clientCouponPassive;
    }

    private boolean extracted(String passiveClientId, MarCoupon marCoupon, DateTime nowDate) {
        log.info("校验优惠券是否可用:clientId:{},couponId:{}", passiveClientId, marCoupon.getId());
        // 校验优惠券是否可用
        if (Objects.isNull(marCoupon)) {
            log.info("优惠券不存在");
            return false;
        }
        // 优惠券删除或者优惠券失效
        if (marCoupon.getStatus() == 0 || marCoupon.getStatus() == 2) {
            log.info("该优惠券已失效");
            return false;
        }
        // 校验优惠券剩余数量
        if (marCoupon.getSurplusCount() <= 0) {
            log.info("优惠券已被领取完");
            return false;
        }

        // 领取后指定天数有效时间处理
        if (null == marCoupon.getValidDays()) {
            // 校验优惠券有效期
            DateTime dateTime = DateUtil.offsetDay(marCoupon.getValidEndTime(), marCoupon.getPostponeDay());
            if (nowDate.isAfter(dateTime)) {
                log.info("优惠券已过期");
                return false;
            }
        }

        // 最大领取
        Integer couponCount = clientCouponMapper.countByClientIdAndCouponId(passiveClientId, marCoupon.getId());
        if (couponCount >= marCoupon.getReceiveCount()) {
            log.info("超过优惠券领取次数");
            return false;
        }
        return true;
    }
}




